package com.group01.advice;

import com.alibaba.fastjson2.JSON;
import com.group01.annotation.SystemLog;
import com.group01.dto.Admin.AdminLoginDTO;
import com.group01.mapper.EsLogMapper;
import com.group01.pojo.EsLog;
import com.group01.pojo.Ip;
import com.group01.utils.CommonUtils;
import com.group01.utils.IP.IpUtils;
import nl.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

/**
 * @Description 系统日志切面
 * @Author 翟玉龙
 * @Date 2024/6/25
 */
@Component
@Aspect
public class SystemLogAdvice {

    /**
     * 注入日志mapper
     */
    private final EsLogMapper esLogMapper;

    public SystemLogAdvice(EsLogMapper esLogMapper) {
        this.esLogMapper = esLogMapper;
    }

    /**
     * 定义切点，标记切点表达式
     */
    @Pointcut("@annotation(com.group01.annotation.SystemLog)")
    public void SystemLogPointCut() {

    }

    /**
     * 环绕通知
     * @param joinPoint 连接点
     * @return Object
     */
    @Around("SystemLogPointCut()")
    public Object SystemLogInfo(ProceedingJoinPoint joinPoint) throws Throwable {
        /*
         * 记录开始时间
         */
        Long startTime = System.currentTimeMillis();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

            /*
             * 创建日志对象
             */
            EsLog log = new EsLog();

            /*
             * 存储登录用户名
             */
            if("POST".equals(request.getMethod()) && "/admin/login".equals(request.getRequestURI())) {
                // 登录请求
                log.setUsername(((AdminLoginDTO) joinPoint.getArgs()[0]).getUsername());
            } else {
                // 操作用户
                log.setUsername(CommonUtils.getLocalName());
            }
            /*
             * 获取注解对象,存储接口描述信息
             */
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            SystemLog systemLog = methodSignature.getMethod().getAnnotation(SystemLog.class);
            log.setBusinessName(systemLog.business());
            System.out.println("接口描述: " + systemLog.business());

            /*
             * 获取请求接口
             */
            log.setRequestUrl(request.getRequestURL().toString());
            System.out.println("请求接口: " + request.getRequestURL().toString());

            /*
             * 请求方式
             */
            log.setRequestMethod(request.getMethod());
            System.out.println("请求方式: " + request.getMethod());

            /*
             * 请求参数 -> json格式
             */
            String json = JSON.toJSONString(joinPoint.getArgs());
            log.setParamsJson(json);
            System.out.println("请求参数：" + json);

            /*
             * 类地址
             */
            log.setClassPath(joinPoint.getSignature().getDeclaringTypeName());
            System.out.println("类地址: " + log.getClassPath());

            /*
             * 方法名
             */
            log.setMethodName(joinPoint.getSignature().getName());
            System.out.println("方法名: " + log.getMethodName());

            /*
             * 分析请求头User-Agent
             */
            UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
            /*
             * 读取系统信息
             */
            log.setOperationName(userAgent.getOperatingSystem().getName());
            System.out.println("系统名称：" + log.getOperationName());
            /*
             * 读取浏览器信息
             */
            log.setBrowserName(userAgent.getBrowser().getName() + " " + userAgent.getBrowserVersion().getVersion());
            System.out.println("浏览器信息：" + log.getBrowserName());

            Ip ip = IpUtils.getIpByRequest(request);
            /*
             * 获取真实ip
             */
            log.setIp(ip.getIp());
            System.out.println("真实ip：" + log.getIp());
            /*
             * 网络运营商
             */
            log.setSource(ip.getAddr());
            System.out.println("网络运营商：" + log.getSource());

            /*
             * 调用核心方法
             */
            Object proceed = joinPoint.proceed();

            /*
             * 响应参数
             */
            log.setResultJson(JSON.toJSONString(proceed));
            System.out.println("响应参数：" + JSON.toJSONString(proceed));

            /*
             * 创建时间
             */
            log.setCreateTime(LocalDateTime.now());
            System.out.println("创建时间：" + log.getCreateTime());

            /*
             * 记录结束时间
             */
            Long endTime = System.currentTimeMillis();
            log.setSpendTime(endTime - startTime);
            System.out.println("执行耗时：" + log.getSpendTime() + "ms");

            /*
             * 保存日志
             */
            esLogMapper.insert(log);
            return proceed;
        } else {
            // 如果没有请求对象，可能是非HTTP环境，需要特殊处理
            throw new IllegalStateException("No HttpServletRequest available in the current thread");
        }
    }
}
